SuperStrict

Framework BRL.GLMax2D
Import BRL.PngLoader
Import BRL.Standardio
Import Pub.GLEW
Import BRL.Random
SetGraphicsDriver GLMax2DDriver()
Global xres#=800
Global yres#=600
Graphics xres,yres,0,0,2


'SetMaskColor(255,255,255)
SetMaskColor(0,0,0)
Global texParticle:Int = GLTexFromPixmap( LoadPixmapPNG("metaball.png") )'GLTexFromPixmap



Global water:waterparticle[] = New waterparticle[5000]
Global num_particles:Int = 0
Global radi# = 8

initPointSprite()

Local tim:Int = 0
Local oldtim:Int = 0
Global dt# = 0


Global e# = 0.9 'restitution

While Not KeyHit(KEY_ESCAPE)
	tim = MilliSecs()
	dt = (tim-oldtim) / 1000.0
	oldtim = tim
	
	If dt > 0.16 dt = 0.16


	'setblend LIGHTBLEND
	'setalpha .5
	
	glEnable(GL_TEXTURE_2D)
	glBindTexture(GL_TEXTURE_2D, texParticle)
	
	'SetBlend alphablend
	glEnable(GL_BLEND)
	glBlendFunc(GL_ONE, GL_ONE) 'Additive blending
	'glBlendFunc GL_SRC_ALPHA,GL_ONE
	'glDisable GL_ALPHA_TEST 'Important! GL turns this on for text methinks. 
	
	glPointSize radi*4'*4.0
	
	glColor4f(0.1,0.2,0.8,.6)

	
	glBegin(GL_POINTS)
		renderworld()
	glEnd()
	
	dynamics()
	collisions()

	Local first:waterparticle = water[0]
	If MouseDown(2)
	If first <> Null

		first.vx = MouseX() - first.px
		first.vy = MouseY() - first.py
		first.px = MouseX()
		first.py = MouseY()
	EndIf
	EndIf
	
	If MouseDown(3) And num_particles > 0 num_particles:-1
	
	If MouseDown(1) And num_particles < Len(water)
		Local newParticle:waterparticle = New waterparticle
		newParticle.px = MouseX() + Rand(-1,1)
		newParticle.py = MouseY() + Rand(-1,1)
		'newParticle.ox = newParticle.px
		'newParticle.oy = newParticle.py
		
		newParticle.ay = 150
		
		water[num_particles] = newParticle
		num_particles:+1
	EndIf
	
	SetAlpha 1
	SetColor 255,255,255
	SetBlend MASKBLEND
	DrawText "dt "+dt, 0, 15
	DrawText "# "+num_particles, 0, 15*2
	Flip
	Cls
Wend


Function renderworld()
	Local i:Int
	For i = 0 Until num_particles
		Local w:waterparticle = water[i]
		glVertex2f(w.px,w.py)
	Next
End Function

Function collisions()
	Local i:Int
	Local j:Int
	
	For i=0 Until num_particles
		Local a:waterparticle = water[i]
		For j=i+1 Until num_particles
			Local b:waterparticle = water[j]
			
			Local dx# = (b.px - a.px)
			Local dy# = (b.py - a.py)
			Local distSq# = dx*dx+dy*dy
			
			Local vxa# = 0.0; Local vya# = 0.0
			Local vxb# = 0.0; Local vyb# = 0.0
			
			If distSq < radi*radi*4 'all balls same size. 2 balls intersect
				Local dist# = Sqr(distSq)
				vxa = a.vx; vya = a.vy;
				vxb = b.vx; vyb = b.vy;
				Local nx# = b.px - a.px
				Local ny# = b.py - a.py
				
				If Abs(dist) > 1e-5
					Local cdx# = nx / dist
					Local cdy# = ny / dist
					
					Local dd# = 2*radi-dist
					
					a.px :- dd*cdx
					a.py :- dd*cdy
					b.px :+ dd*cdx
					b.py :+ dd*cdy
					Local am# = Sqr( a.vx*a.vx + a.vy*a.vy )
					
					If Abs(am) > 1e-5
						'dot prod mult by restitution
						Local cosam# = cdx * a.vx + cdy * a.vy * e
						vxa :- cdx*cosam
						vya :- cdy*cosam
						vxb :+ cdx*cosam
						vyb :+ cdy*cosam
					EndIf
					
					Local bm# = Sqr( b.vx*b.vx + b.vy*b.vy )
					
					If Abs(bm) > 1e-5
						'dot prod mult by restitution
						Local cosam# = cdx * b.vx + cdy * b.vy * e
						vxa :+ cdx*cosam
						vya :+ cdy*cosam
						vxb :- cdx*cosam
						vyb :- cdy*cosam
					EndIf
					
				EndIf
				
				a.vx = vxa
				a.vy = vya
				b.vx = vxb
				b.vy = vyb
			EndIf
				

		Next
	Next
End Function

Function dynamics()

	
	'Dynamics
	'incompressible. chrystal-like behaviour. "stolen" from paul bourkes site.
	Local i:Int
	For i=0 Until num_particles
		Local w:waterparticle = water[i]
		'verlet integration
		Local tempx# = w.ax*dt
		w.px = w.px + dt*(w.vx+tempx*.5)
		w.vx = w.vx + tempx

		Local tempy# = w.ay*dt
		w.py = w.py + dt*(w.vy+tempy*.5)
		w.vy = w.vy + tempy
		
		'Boundary conditions
		If w.px < w.r 
			w.px = w.r 
			w.vx = -w.vx * e
		EndIf
		
		If w.py < w.r 
			w.py = w.r 
			w.vy = -w.vy * e
		EndIf
		
		If w.px > xres-w.r
			w.px = xres-w.r 
			w.vx = -w.vx * e
		EndIf
		
		If w.py > yres-w.r 
			w.py = yres-w.r	 
			w.vy = -w.vy * e
		EndIf
	Next

	
End Function

Function dist2D:Float(x1#,y1#,x2#,y2#)
	Return Sqr( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) )
End Function

Function distSquare:Float(x1#,y1#,x2#,y2#)
	Return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)
End Function

Type waterparticle
	Field ox#, oy#
	Field px#, py#
	Field vx#, vy#
	Field ax#, ay#
	Field r# = radi
End Type


Function checkError()
	Local checkedAllErrors:Int = False
	Local glerrorList$ = ""
	Local numErrors:Int = 0
	While checkedAllErrors=False
		Local errorCode:Int = glGetError()
		If errorCode = GL_NO_ERROR
			checkedAllErrors = True
		Else
			numErrors = numErrors + 1
			If errorCode = GL_INVALID_ENUM glerrorList:+" invalid enum "
			If errorCode = GL_INVALID_VALUE glerrorList:+" invalid value "
			If errorCode = GL_INVALID_OPERATION glerrorList:+" invalid operation "
			If errorCode = GL_STACK_OVERFLOW glerrorList:+" stack overflow "
			If errorCode = GL_STACK_UNDERFLOW glerrorList:+" stack underflow "
			If errorCode = GL_OUT_OF_MEMORY glerrorList:+" GL_OUT_OF_MEMORY "
			If errorCode = GL_TABLE_TOO_LARGE glerrorList:+" GL_TABLE_TOO_LARGE "
		EndIf
	Wend
	If glerrorList <> ""
		Print "#"+numErrors +" glGetErrors this frame: "+glerrorList
	EndIf
End Function

Function initPointSprite()
'Glew, opengl extension wrangler is used To se If an extension is supported.
	glewInit()	
	If(GL_POINT_SPRITE)
		Print "GL_POINT_SPRITE is supported"
		glEnable(GL_POINT_SPRITE)
	Else 
		Print "GL_POINT_SPRITE is Not supported"
		End
	EndIf
	'glEnable( GL_BLEND )
	'glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) 'additive without overblending
	'glPointSize( 30.0 )
	
	glActiveTexture(GL_TEXTURE0);
	glEnable( GL_TEXTURE_2D );
	glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); 'Generates tex coords for Point Sprite
	'modes: <a href="http://www.khronos.org/opengles/documentation/opengles1_0/html/glTexEnv.html" target="_blank">http://www.khronos.org/opengles/documentation/opengles1_0/html/glTexEnv.html</a>
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);  'GL_MODULATE, GL_DECAL, GL_BLEND, Or GL_REPLACE.
	
	'Local color:Float[] = [1.0, 0.0, 0.0]
	'glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color[0] )
	'glBindTexture(GL_TEXTURE_2D, texture_name);
End Function

